package com.tuyrt.`as`.proj.main.http

import com.tuyrt.hi.library.restful.HiCall
import com.tuyrt.hi.library.restful.HiCallback
import com.tuyrt.hi.library.restful.HiRequest
import com.tuyrt.hi.library.restful.HiResponse
import okhttp3.FormBody
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.http.*


class RetrofitCallFactory(val baseUrl: String) : HiCall.Factory {

    private var apiService: ApiService
    private var hiConvert: GsonConvert

    init {
        val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .build()

        apiService = retrofit.create(ApiService::class.java)
        hiConvert = GsonConvert()
    }

    override fun newCall(request: HiRequest): HiCall<Any> {
        return RetrofitCall(request)
    }

    internal inner class RetrofitCall<T>(val request: HiRequest) : HiCall<T> {

        override fun execute(): HiResponse<T> {
            val realCall = createRealCall(request)
            val response = realCall.execute()
            return parseResponse(response)
        }

        override fun enqueue(callback: HiCallback<T>) {
            val realCall = createRealCall(request)
            realCall.enqueue(object : Callback<ResponseBody> {
                override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                    val hiResponse = parseResponse(response)
                    callback.onSuccess(hiResponse)
                }

                override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                    callback.onFailed(t)
                }
            })
        }

        private fun parseResponse(response: Response<ResponseBody>): HiResponse<T> {
            var rawData: String? = null
            if (response.isSuccessful) {
                val body = response.body()
                if (body != null) {
                    rawData = body.string()
                }
            } else {
                val body = response.errorBody()
                if (body != null) {
                    rawData = body.string()
                }
            }
            return hiConvert.convert(rawData!!, request.returnType!!)
        }

        private fun createRealCall(request: HiRequest): Call<ResponseBody> {
            if (request.httpMethod == HiRequest.METHOD.GET) {
                return apiService.get(request.headers, request.endPointUrl(), request.parameters)
            } else if (request.httpMethod == HiRequest.METHOD.POST) {
                val requestBody: RequestBody = buildRequestBody(request)
                return apiService.post(request.headers, request.endPointUrl(), requestBody)
            } else if (request.httpMethod == HiRequest.METHOD.PUT) {
                val requestBody: RequestBody = buildRequestBody(request)
                return apiService.put(request.headers, request.endPointUrl(), requestBody)
            } else if (request.httpMethod == HiRequest.METHOD.DELETE) {
                return apiService.delete(request.headers, request.endPointUrl())
            } else {
                throw IllegalStateException("HiRestful only support GET POST for now , url:${request.endPointUrl()}")
            }
        }

        private fun buildRequestBody(request: HiRequest): RequestBody {
            val parameters: MutableMap<String, String>? = request.parameters
            val builder = FormBody.Builder()
            val jsonObject = JSONObject()
            if (parameters != null) {
                for ((key, value) in parameters) {
                    if (request.formPost) {
                        builder.add(key, value)
                    } else {
                        jsonObject.put(key, value)
                    }
                }
            }

            return if (request.formPost) {
                builder.build()
            } else {
                //bugfix: request-header   content-type="application/json;charset=utf-8"
                RequestBody.create(MediaType.parse("application/json;charset=utf-8"), jsonObject.toString())
            }
        }
    }

    interface ApiService {
        @GET
        fun get(
            @HeaderMap headers: MutableMap<String, String>?,
            @Url url: String,
            @QueryMap(encoded = true) parameters: MutableMap<String, String>?,
        ): Call<ResponseBody>

        @POST
        fun post(
            @HeaderMap headers: MutableMap<String, String>?,
            @Url url: String,
            @Body body: RequestBody?,
        ): Call<ResponseBody>

        @PUT
        fun put(
            @HeaderMap headers: MutableMap<String, String>?,
            @Url url: String,
            @Body body: RequestBody?,
        ): Call<ResponseBody>

        @DELETE//不可以携带requestbody
        fun delete(
            @HeaderMap headers: MutableMap<String, String>?,
            @Url url: String,
        ): Call<ResponseBody>
    }
}